
#include <cstdio>
#include <BUdpSocket>
#include "member_BSocket.h"
#include "member_BUdpSocket.h"

using namespace BWE;

#define member					(*(member_BUdpSocket*)_ptr)
#define member_allocate()		_ptr = new member_BUdpSocket(this)
#define member_release()		delete (member_BUdpSocket*)_ptr

#ifdef _LINUX_
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

BUdpSocket::BUdpSocket()
{
	member_allocate();
	socket_member(this)->sock = ::socket(AF_INET, SOCK_DGRAM, 0);
}
BUdpSocket::~BUdpSocket()
{
	member_release();
}

BUdpSocket::Type BUdpSocket::type() const
{
	return UdpSocket;
}

bool BUdpSocket::sendTo(const char* data, int length)
{
	::sendto(socket_member(this)->sock, data, length, 0, 0, 0);
	return true;
}
bool BUdpSocket::recvFrom(char* data, int& length)
{
	::recvfrom(socket_member(this)->sock, data, length, 0, 0, 0);
	return true;
}

#endif

#ifdef _WINDOWS_SYSTEM_

BUdpSocket::BUdpSocket()
{
	member_allocate();
	socket_member(this)->sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
BUdpSocket::~BUdpSocket()
{
	member_release();
}

BUdpSocket::Type BUdpSocket::type() const
{
	return UdpSocket;
}

bool BUdpSocket::bind(const BString& ip, int port)
{
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	InetPton(AF_INET, ip.cstr(), &addr.sin_addr.s_addr);

	int ret = ::bind(socket_member(this)->sock, (sockaddr*)&addr, sizeof(addr));
	if (ret == SOCKET_ERROR)
	{
		int errorCode = WSAGetLastError();
		perror("bind");
		return false;
	}
	return true;
}

bool BUdpSocket::sendTo(const BString& ip, int port, const char* data, int size)
{
	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());

	int len = ::sendto(socket_member(this)->sock, data, size, 0, (sockaddr*)&to_addr, sizeof(sockaddr));
	return true;
}
bool BUdpSocket::recvFrom(const BString& ip, int port, char* data, int& size)
{
	sockaddr_in to_addr;
	memset(&to_addr, 0, sizeof(sockaddr_in));
	to_addr.sin_family = AF_INET;
	to_addr.sin_port = htons(port);
	to_addr.sin_addr.S_un.S_addr = inet_addr(ip.cstr());
	int from_addr_len = sizeof(sockaddr_in);

	int len = ::recvfrom(socket_member(this)->sock, data, size, 0, (sockaddr*)&to_addr, &from_addr_len);
	return true;
}

#endif
